package com.sc.nft.config;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.sc.nft.constant.TableNameConstants;
import com.sc.nft.util.TableNameContext;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
        scannerConfigurer.setBasePackage("com.sc.nft.mapper*");
        return scannerConfigurer;
    }

    @Bean
    public MybatisPlusInterceptor myOptimisticLockerInnerInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor());
        return interceptor;

    }

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor page = new PaginationInterceptor();
        page.setLimit(-1);
        page.setDialectType("mysql");
        return page;
    }

    private final TableNameHandler handler = (sql, tableName) -> {
        // 动态指定分区，不指定则使用原表名
        final String partition = TableNameContext.getPartition();
        if (StrUtil.isBlank(partition)) {
            return tableName;
        }

        // 容错处理，避免 `` 造成表名拼接错误
        if (tableName.contains("`")) {
            tableName = tableName.replaceAll("`", "");
        }

        // 分区表存放于 metago_partition 库中，由于 @DS 机制实现的动态数据源受 Spring 事务机制影响，
        // 这里调整为不再使用多数据源，直接在表名前拼接分区库名方式实现（这意味着分区库必须存在于主库同一实例上）
        String prefix = "";
        if (!StrUtil.contains(tableName, ".")) {
            prefix = "metago_partition.";
        }
        return String.format("%s%s_%s", prefix, tableName, partition);
    };

    /**
     * <a href="https://baomidou.com/plugins/dynamic-table-name/">动态表名插件</a>
     */
    private DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {

        // 动态表名插件，结合自定义ID生成器实现水平分表功能
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();

        Map<String, TableNameHandler> map = new HashMap<>();

        TableNameConstants.allTableNames().forEach(table -> map.put(table, handler));

        dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);

        return dynamicTableNameInnerInterceptor;
    }

}
